package helipay.api.jedis;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.PreDestroy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.Pipeline;

/**
 * Redis操作接口
 * 
 */
@Component
@Scope("singleton")
public class RedisSentinelAPI {

	private Log logger = LogFactory.getLog(RedisSentinelAPI.class);

	@Value("${redis.maxActive}")
	private String maxActive;
	@Value("${redis.maxIdle}")
	private String maxIdle;
	@Value("${redis.maxWait}")
	private String maxWait;
	@Value("${redis.testOnBorrow}")
	private String testOnBorrow;

	//@Value("${redis.hosts}")
	//private String hosts;
	@Value("${redis.port}")
	private String port;

	private static JedisSentinelPool pool=null;

	public enum Db {
		DEFAULT(0), // 默认数据库
		;
		private int db;

		private Db(int db) {
			this.db = db;
		}

		public int toIntValue() {
			return this.db;
		}

		public Db toDb(int db) {
			if (DEFAULT.db == db) {
				return Db.DEFAULT;
			} else {
				throw new RuntimeException("未知类型[" + db + "].");
			}
		}
	}

	//@PostConstruct
	public void init() {
		logger.info("init");

		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxActive(Integer.valueOf(maxActive));
		config.setMaxIdle(Integer.valueOf(maxIdle));
		config.setMaxWait(Integer.valueOf(maxWait));
		config.setTestOnBorrow(Boolean.valueOf(testOnBorrow));

		Set<String> sentinels = new HashSet<String>();
		sentinels.add("172.168.11.46:"+port+"");
		sentinels.add("172.168.11.58:"+port+"");
		pool = new JedisSentinelPool("mymaster", sentinels, config);
	}

	@PreDestroy
	public void destroy() {
		logger.info("destroy");

		pool.destroy();
	}

	/**
	 * 构建redis连接池
	 * 
	 * @return JedisSentinelPool
	 */
	public JedisSentinelPool getPool(String key) {
		// int idx = key.hashCode() % 4;
		return pool;
	}

	/**
	 * 返还到连接池
	 * 
	 * @param pool
	 * @param redis
	 */
	public void returnResource(JedisSentinelPool pool, Jedis redis) {
		if (pool != null) {
			if (redis != null) {
				redis.select(Db.DEFAULT.db);
				pool.returnResource(redis);
			}
		}
	}

	public void returnBrokenResource(JedisSentinelPool pool, Jedis redis) {
		if (pool != null) {
			pool.returnBrokenResource(redis);
		}
	}

	public boolean del(String key) {
		return del(Db.DEFAULT, key);
	}

	public boolean del(RedisSentinelAPI.Db db, String key) {
		JedisSentinelPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.del(key) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public String get(String key) {
		return get(Db.DEFAULT, key);
	}

	public String get(RedisSentinelAPI.Db db, String key) {
		JedisSentinelPool pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.get(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public boolean set(String key, String value) {
		return set(Db.DEFAULT, key, value);
	}

	public boolean set(RedisSentinelAPI.Db db, String key, String value) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			jedis.set(key, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public String lpop(String key) {
		return lpop(Db.DEFAULT, key);
	}

	public String lpop(Db db, String key) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.lpop(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public boolean rpush(String key, String... values) {
		return rpush(Db.DEFAULT, key, values);
	}

	public boolean rpush(Db db, String key, String... values) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.rpush(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}

	public boolean lpush(String key, String... values) {
		return lpush(Db.DEFAULT, key, values);
	}

	public boolean lpush(Db db, String key, String... values) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.lpush(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}

	public List<String> lrange(String key, long start, long end) {
		return lrange(Db.DEFAULT, key, start, end);
	}

	public List<String> lrange(Db db, String key, long start, long end) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.lrange(key, start, end);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public String ltrim(String key, long start, long end) {
		return ltrim(Db.DEFAULT, key, start, end);
	}

	public String ltrim(Db db, String key, long start, long end) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.ltrim(key, start, end);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return null;
	}

	public boolean lrem(String key, long count, String value) {
		return lrem(Db.DEFAULT, key, count, value);
	}

	public boolean lrem(Db db, String key, long count, String value) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.lrem(key, count, value) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}

	public long llen(String key) {
		return llen(Db.DEFAULT, key);
	}

	public long llen(Db db, String key) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;
		long len = 0;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			len = jedis.llen(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return len;
	}

	public boolean expire(String key, int seconds) {
		return expire(Db.DEFAULT, key, seconds);
	}

	public boolean expire(RedisSentinelAPI.Db db, String key, int seconds) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.expire(key, seconds) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return true;
	}

	public boolean srem(String key, String... values) {
		return srem(Db.DEFAULT, key, values);
	}

	public boolean srem(RedisSentinelAPI.Db db, String key, String... values) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.srem(key, values) > 0;

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public boolean sadd(String key, String... members) {
		return sadd(Db.DEFAULT, key, members);
	}

	public boolean sadd(RedisSentinelAPI.Db db, String key, String... members) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			jedis.sadd(key, members);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public Set<String> smembers(String key) {
		return smembers(Db.DEFAULT, key);
	}

	public Set<String> smembers(RedisSentinelAPI.Db db, String key) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.smembers(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return null;
	}

	public boolean sismember(String key, String member) {
		return this.sismember(Db.DEFAULT, key, member);
	}

	public boolean sismember(RedisSentinelAPI.Db db, String key, String member) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.sismember(key, member);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return false;
	}
	
	public boolean hset(String key, String field, String value) {
		return hset(Db.DEFAULT, key, field, value);
	}

	public boolean hset(RedisSentinelAPI.Db db, String key, String field, String value) {

		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			jedis.hset(key, field, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public boolean hmset(String key, Map<String, String> hash) {
		return hmset(Db.DEFAULT, key, hash);
	}

	public boolean hmset(RedisSentinelAPI.Db db, String key, Map<String, String> hash) {

		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			jedis.hmset(key, hash);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public int ttl(String key) {
		return ttl(Db.DEFAULT, key);
	}

	public int ttl(RedisSentinelAPI.Db db, String key) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;
		int result = 0;
		
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			result = jedis.ttl(key).intValue();

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return result;
	}

	public String hget(String key, String field) {
		return hget(Db.DEFAULT, key, field);
	}

	public String hget(RedisSentinelAPI.Db db, String key, String field) {

		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		String value = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			value = jedis.hget(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return value;
	}

	public boolean hexists(String key, String field) {
		return hexists(Db.DEFAULT, key, field);
	}
	
	public boolean hexists(RedisSentinelAPI.Db db, String key, String field) {

		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.hexists(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return false;
	}
	
	public Map<String, String> hgetAll(String key) {
		return hgetAll(Db.DEFAULT, key);
	}

	public Map<String, String> hgetAll(RedisSentinelAPI.Db db, String key) {

		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		Map<String, String> hash = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			hash = jedis.hgetAll(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return hash;
	}

	public boolean hdel(String key, String field) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		long value = 0;

		try {

			pool = getPool(key);
			jedis = pool.getResource();

			value = jedis.hdel(key, field);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return (value > 0);
	}

	public List<String> hvals(String key) {
		return hvals(Db.DEFAULT, key);
	}

	public List<String> hvals(RedisSentinelAPI.Db db, String key) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;
		List<String> result = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			result = jedis.hvals(key);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return result;
	}

	public long hincrBy(String key, String field, long value) {
		return hincrBy(Db.DEFAULT, key, field, value);
	}

	public long hincrBy(RedisSentinelAPI.Db db, String key, String field, long value) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;
		try {

			pool = getPool(key);
			jedis = pool.getResource();
			jedis.select(db.toIntValue());

			return jedis.hincrBy(key, field, value);

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}
		return 0;
	}

	public boolean batchHset(String key, Map<String, String> hashDataMap) {
		return batchHset(Db.DEFAULT, key, hashDataMap);
	}

	/**
	 * 批量insert hash
	 * 
	 * @param key
	 * @param hashDataMap
	 *            k->field , v->value
	 */
	public boolean batchHset(RedisSentinelAPI.Db db, String key, Map<String, String> hashDataMap) {
		JedisSentinelPool  pool = null;
		Jedis jedis = null;

		try {

			pool = getPool(key);
			jedis = pool.getResource();

			jedis.select(db.toIntValue());

			Pipeline pipeline = jedis.pipelined();

			for (Map.Entry<String, String> data : hashDataMap.entrySet()) {
				pipeline.hset(key, data.getKey(), data.getValue());
			}

			pipeline.sync();

		} catch (Exception e) {
			returnBrokenResource(pool, jedis);
			logger.error(e.getMessage(), e);
		} finally {
			returnResource(pool, jedis);
		}

		return true;
	}

	public class Page {
		private int start;
		private int size;

		public Page(int start, int size) {
			start--;

			if (start < 0) {
				start = 0;
			}

			size = start + size - 1;

			if (size < 0) { // redis 0,0 是取第一个
				start = Integer.MAX_VALUE;
				size = Integer.MAX_VALUE;
			}

			this.start = start;
			this.size = size;
		}

		public int getStart() {
			return start;
		}

		public int getSize() {
			return size;
		}
	}

	public Page getPage(int mysqlStart, int mysqlSize) {
		return new Page(mysqlStart, mysqlSize);
	}

	public static void main(String[] args) {
		Page p = new RedisSentinelAPI().getPage(0, 1);
		System.out.println(p.getStart() + "," + p.getSize());

		// Map<String, String> hashDataMap = new HashMap<String, String>();
		// hashDataMap.put("1", "yechong");
		// hashDataMap.put("2", "carlye");
		//
		// RedisAPI.batchHset("keewee-test", hashDataMap);
	}
}
